/*
 * WeakRef.h
 *
 *	Author: stravant
 *	Description:
 *		
 */

#ifndef WEAKREF_H_
#define WEAKREF_H_

#include "../core/RefCounted.h"

namespace priv {

//reference counted "flag" that shows whether there are references to
//a weak referencable thing or not. Once all weak-references holding
//the flag go out of scope the flag will zero out the pointer to it
//that resides in the WeakRefFlagIssuer that issued it.
template <class T>
class WeakRefFlag: public RefCountedThreadsafe<WeakRefFlag<T>> {
public:
	~WeakRefFlag() {
		*Handle = 0;
	}
	WeakRefFlag** Handle;
	void invalidate() {
		Handle = 0;
	}
};


//"issues" a single flag object and tracks it's lifetime, as well as
//providing acccess to the flag.
//while there are references to a a referenceissuer's held flag, from
//weak-pointers, it will hold a reference to the referenceissuer as
//well.
template <class T>
class WeakRefFlagIssuer {
public:
	WeakRefFlagIssuer() {}
	~WeakRefFlagIssuer() {invalidate();}

	priv::WeakRefFlag<T>* getRefFlag() const {
		if (!mFlag) {
			mFlag = new priv::WeakRefFlag<T>;
			mFlag->Handle = &mFlag;
		}
		return mFlag;
	}

	bool hasWeakRef() const {return mFlag != 0; }

	void invalidate() {
		if (mFlag) {
			mFlag->invalidate();
			mFlag = 0;
		}
	}
private:
	mutable priv::WeakRefFlag<T>* mFlag;
};

}


//A weak-reference, hold a reference to a flag, which shows whether the pointer
//hold by the WeakRef is valid.
template <class T>
class WeakRef {
public:
	WeakRef(): mPtr(0) {}
	template <class U>
	WeakRef(const WeakRef<U>& other): mFlag(other.mFlag), mPtr(other.mPtr) {}
	~WeakRef() {}

	T* get() const {return (mFlag && mFlag->Handle) ? mPtr : 0; }
	operator T*() const {return get(); }
	T* operator->() const {return get(); }
	void reset() {mFlag = 0; }

	//internal
	WeakRef(T* obj, priv::WeakRefFlag<T>* flag): mFlag(flag), mPtr(obj) {}
private:
	Ref<priv::WeakRefFlag<T>> mFlag;
	T* mPtr;
};


//WeakBase, things can inheret from this to provide weak-referencing
//of themselves.
template <class T>
class WeakBase {
public:
	WeakBase() {}
	~WeakBase() {
		mIssuer.invalidate();
	}

	WeakRef<T> getWeakRef() const {
		return WeakRef<T>(static_cast<T*>(this), mIssuer.getRefFlag());
	}
private:
	priv::WeakRefFlagIssuer<T> mIssuer;
};


//WeakFactory, provides weak-references to some arbitrary data.
template <class T>
class WeakFactory {
public:
	WeakFactory(T* data): mData(data) {}
	~WeakFactory() {
		mIssuer.invalidate();
	}

	WeakRef<T> getWeakRef() {
		return WeakRef<T>(mData, mIssuer.getRefFlag());
	}

	bool hasWeakRefs() {
		return mIssuer.hasWeakRef();
	}

	void invalidateWeakRefs() {
		return mIssuer.invalidate();
	}
private:
	priv::WeakRefFlagIssuer<T> mIssuer;
	T* mData;
};

#endif /* WEAKREF_H_ */
